﻿/*!
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

using System;
using System.Globalization;
using System.Text;

namespace Pittypat
{
    /// <summary>
    /// 提供针对 <see cref="IJson"/> 类型值的辅助方法。
    /// </summary>
    public static class Json
    {
        /// <summary>
        /// 将指定的字符串按 JSON 要求进行转义或编码。不会在前后添加 "" 双引号。
        /// </summary>
        /// <param name="s">要转移的目标字符串。</param>
        /// <returns>转义或编码后的符合 JSON 要求的字符串。</returns>
        public static string Escape(string s)
        {
            if (string.IsNullOrEmpty(s))
            {
                return "";
            }

            StringBuilder b = null;
            int startIndex = 0;
            int count = 0;
            char c = '\0';
            int len = s.Length;

            for (int i = 0; i < len; i++)
            {
                c = s[i];

                if (c < 0x20 || c == '\"' || c == '\\' || c == '/')
                {
                    if (b == null)
                    {
                        b = new StringBuilder(len + 5);
                    }

                    if (count > 0)
                    {
                        b.Append(s, startIndex, count);
                    }

                    startIndex = i + 1;
                    count = 0;
                }

                switch (c)
                {
                    case '\"':
                        b.Append("\\\"");
                        break;
                    case '\\':
                        b.Append("\\\\");
                        break;
                    case '/':
                        b.Append("\\/");
                        break;
                    case '\r':
                        b.Append("\\r");
                        break;
                    case '\t':
                        b.Append("\\t");
                        break;
                    case '\n':
                        b.Append("\\n");
                        break;
                    case '\b':
                        b.Append("\\b");
                        break;
                    case '\f':
                        b.Append("\\f");
                        break;
                    default:
                        if (c < 0x20)
                        {
                            b.Append("\\u");
                            b.Append(((int)c).ToString("x4", CultureInfo.InvariantCulture));
                        }
                        else
                        {
                            ++count;
                        }
                        break;
                }
            }

            if (b == null)
            {
                return s;
            }

            if (count > 0)
            {
                b.Append(s, startIndex, count);
            }

            return b.ToString();
        }

        /// <summary>
        /// 获取指定值的类型名称，总是为小写形式。
        /// </summary>
        /// <param name="value">IJson 值。</param>
        /// <returns>类型名称字符串，如果 value 为 null，则返回字符串 "null"。</returns>
        /// <remarks>此方法返回的字符串不是 C# 中类型的字符串，而是自定义的类型字符串，以便返回的字符串与 Java 中返回的类型字符串是一致。</remarks>
        internal static string GetTypeName(IJson value)
        {
            if (value == null)
            {
                return "null";
            }

            Type type = value.GetType();

            if (type == typeof(@string))
            {
                return "string";
            }

            if (type == typeof(@int32))
            {
                return "int32";
            }

            if (type == typeof(@bool))
            {
                return "bool";
            }

            if (type == typeof(@datetime))
            {
                return "datetime";
            }

            if (type == typeof(@uuid))
            {
                return "uuid";
            }

            if (type == typeof(@binary))
            {
                return "binary";
            }

            if (type == typeof(@date))
            {
                return "date";
            }

            if (type == typeof(@decimal))
            {
                return "decimal";
            }

            if (type == typeof(@float32))
            {
                return "float32";
            }

            if (type == typeof(@float64))
            {
                return "float64";
            }

            if (type == typeof(@int16))
            {
                return "int16";
            }

            if (type == typeof(@int64))
            {
                return "int64";
            }

            if (type == typeof(@interval))
            {
                return "interval";
            }

            if (type == typeof(@time))
            {
                return "time";
            }

            if (type == typeof(NotificationList))
            {
                return "notificationlist";
            }

            if (type == typeof(NavList))
            {
                return "navlist";
            }

            if (type == typeof(DynamicModel))
            {
                return "dynamicmodel";
            }

            if (typeof(IUser).IsAssignableFrom(type))
            {
                return "user";
            }

            if (typeof(INotification).IsAssignableFrom(type))
            {
                return "notification";
            }

            if (typeof(INavApp).IsAssignableFrom(type))
            {
                return "navapp";
            }

            if (typeof(INavModule).IsAssignableFrom(type))
            {
                return "navmodule";
            }

            if (type.IsSubclassOf(typeof(DataModel)) || type.IsSubclassOf(typeof(FunctionArgs)))
            {
                return type.FullName.ToLower();
            }

            if (type.IsGenericType)
            {
                var td = type.GetGenericTypeDefinition();
                if (td == typeof(DataList<>))
                {
                    return string.Format("list<{0}>", type.GetGenericArguments()[0].FullName.ToLower());
                }

                if (td == typeof(FunctionModel<>))
                {
                    return "functionmodel";
                }
            }

            return type.FullName.ToLower();
        }
    }
}
